`timescale 1ps/1ps
module encode(
    input  clk
,   input  rst_n

/* state ctrl 脉冲*/
,   input  en
,   output done
,   input  [127:0]txt
,   output [127:0]out

/* key regfile */
,   output reg [3:0] key_addr
,   input  [127:0]   key_in

/* sbox share port*/
,   output [2:0]    sbox_cmd        
,   output [127:0]  sbox_addr           
,   input  [31:0]   sbox_out_32
);
wire   once_done;
// TODO: key 的切换
parameter   IDLE    =    4'd0,
            S1      =    4'd1, // first
            S2      =    4'd2,
            S3      =    4'd3,
            S4      =    4'd4,
            S5      =    4'd5,
            S6      =    4'd6,
            S7      =    4'd7,
            S8      =    4'd8,
            S9      =    4'd9,
            S10     =    4'd10,
            S11     =    4'd11; // end

reg [3:0]cur_state;
reg [3:0]nxt_state;
always @(posedge clk or negedge rst_n) begin
    if(!rst_n)
        cur_state <= IDLE;
    else
        cur_state <= nxt_state;
end

always @(*) begin
    case(cur_state)
        IDLE:if(en)        nxt_state = S1;else nxt_state = IDLE ;
        S1:  if(once_done) nxt_state = S2;else nxt_state = S1   ;
        S2:  if(once_done) nxt_state = S3;else nxt_state = S2   ;
        S3:  if(once_done) nxt_state = S4;else nxt_state = S3   ;
        S4:  if(once_done) nxt_state = S5;else nxt_state = S4   ;
        S5:  if(once_done) nxt_state = S6;else nxt_state = S5   ;
        S6:  if(once_done) nxt_state = S7;else nxt_state = S6   ;
        S7:  if(once_done) nxt_state = S8;else nxt_state = S7   ; 
        S8:  if(once_done) nxt_state = S9;else nxt_state = S8   ;
        S9:  if(once_done) nxt_state = S10;else nxt_state = S9  ;  
        S10: if(once_done) nxt_state = S11;else nxt_state = S10 ;  
        S11: if(once_done) nxt_state = IDLE;else nxt_state = S11;
        default:nxt_state = IDLE;
    endcase 
end
always @(*) begin
    case(cur_state)
        S1:  key_addr = 4'd0;
        S2:  key_addr = 4'd1;
        S3:  key_addr = 4'd2;
        S4:  key_addr = 4'd3;
        S5:  key_addr = 4'd4;
        S6:  key_addr = 4'd5;
        S7:  key_addr = 4'd6;
        S8:  key_addr = 4'd7;
        S9:  key_addr = 4'd8;
        S10: key_addr = 4'd9;
        S11: key_addr = 4'd10;
        default:key_addr = 4'd0;
    endcase
end

reg once_en;
always @(posedge clk or negedge rst_n) begin
    if(!rst_n)
        once_en <= 1'b0; 
    else if((cur_state == IDLE && nxt_state == S1) || 
            (cur_state ==   S1 && nxt_state == S2) || 
            (cur_state ==   S2 && nxt_state == S3) || 
            (cur_state ==   S3 && nxt_state == S4) || 
            (cur_state ==   S4 && nxt_state == S5) || 
            (cur_state ==   S5 && nxt_state == S6) || 
            (cur_state ==   S6 && nxt_state == S7) || 
            (cur_state ==   S7 && nxt_state == S8) || 
            (cur_state ==   S8 && nxt_state == S9) || 
            (cur_state ==   S9 && nxt_state == S10)||
            (cur_state ==  S10 && nxt_state == S11))
        once_en <= 1'b1;
    else
        once_en <= 1'b0;
end

wire first = cur_state == S1;
wire last  = cur_state == S11;
assign done = cur_state == S11 && nxt_state == IDLE;

reg [127:0]txt_;
always@(posedge clk or negedge rst_n)
    if(!rst_n)
        txt_ <= 'd0;
    else if(en)
        txt_ <= txt;
    else if(once_done)
        txt_ <= out;

encode_once  u_encode_once (
    .clk                     ( clk           ),
    .rst_n                   ( rst_n         ),
    .en                      ( once_en       ),
    .first                   ( first         ),
    .last                    ( last          ),
    .txt                     ( txt_          ),
    .key                     ( key_in        ),
    .sbox_out_32             ( sbox_out_32   ),

    .done                    ( once_done     ),
    .out                     ( out           ),
    .cmd                     ( sbox_cmd      ),
    .addr                    ( sbox_addr     )
);

endmodule